package com.kerwin.utils;

import com.kerwin.config.CrmTokenProperties;
import com.kerwin.entity.returnjson.E;
import com.kerwin.exception.HandlerException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.crypto.SecretKey;
import java.security.Key;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;



// We need a signing key, so we'll create one just for this example. Usually
// the key would be read from your application configuration instead.

@Component
/*我在这里需要把我自定义的token头  从配置文件读取出来*/
public class TokenUtil  implements InitializingBean {
    private static String key = "4+oLqLdGwYL608gMCijXvyoqO4v/vxePjKAavrdftUI=";
    /*1、全局有效时间*/
    /*1000毫秒换算成秒等于1秒。 60*1000 是一秒*/
    /*给他设置好默认值，要是初始化没加载上，就用默认值*/
    private static Long EXP_TIME = 10 * 60 * 1000L;
    /*指定一个两秒失效的过期时间*/
    private Long twoSecondExpTime = 2 * 1000L;
    /*提出来的是map的key*/
    /*这个字符串已经失效，我已经在配置文件里面指定了，不要写死的*/
    public static  String TOKEN_HEADER ;
    public static  String TOKEN_PHONE ;





    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, HandlerException {
        /*要把秘钥提示去，防止每次生成都是新的*/

        Class<?> aClass = Class.forName("com.kerwin.utils.TokenUtil");
        TokenUtil o = (TokenUtil) aClass.newInstance();
        /*生成秘钥字符串*/
        //o.getKeyString();


        /*3、为了往token里面放 自定义数据 这里建立一个map集合*/
        //HashMap<String, String> claims = new HashMap<>();
        /*要根据key来取 把key提出来*/
        //claims.put(TOKEN_PHONE, "18012341234");
        //String myToken = o.CreatingJws(claims);
       // System.out.println("打印生成的token "+myToken);

        /*在这里解析得到我的电话号*/
        Claims claims2 = o.parseToken("eyJhbGciOiJIUzI1NiJ9.eyJQaG9uZSI6IjE4MDEyMzQxMjM0IiwiZXhwIjoxNjUzMTAwNTQ0fQ.ziceZlcweoKJ4UTodZnvqKr7ReTCSCerBBENzVzFe7g");
        //Claims claims1 = o.parseToken(myToken);
        /*5、测试不用写签发时间，也能过期*/
        System.out.println(claims2.get(TOKEN_PHONE));


    }

    /*把写死的token 头，从配置文件里面替换*/


    public static String CreatingJws(String userPhone_) {
        String userPhone = SpringContextUtil.getBean(CrmTokenProperties.class).getUserPhone();
        /*设置有效时间  有效时间=当前时间+持续时间*/
        /*当前时间*/
        Date current = new Date();
        /*持续时间*/
        Date expDate = new Date(current.getTime() + EXP_TIME);
        /*持续两秒的过期时间*/
        /*Date expDate = new Date(current.getTime() + twoSecondExpTime);*/

        /*2、对字符串解密 变成key*/
        SecretKey secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(key));

        /*传入一个map集合*/
        Map<String, String> yourPhone=new HashMap<String, String>();
        /*这里是从配置文件里面拿到的属性*/
        yourPhone.put(userPhone,userPhone_);

        String jws = Jwts.builder()
                /*除了标准签名信息外*/
                /*可以写入自定义信息，传入map集合*/
                /*为什么要用map集合  <userPhone，手机号(因为手机号是唯一的)>*/
                /*自定义签名必须在标准签名之前，不然会覆盖标准签名*/
                .setClaims(yourPhone)
                /*有效时间*/
                /*1、需要指定一个全局的时间变量，设置有效时间*/
                .setExpiration(expDate)
                /*5、设置当前的签发时间*/
                .setIssuedAt(current)
                /*这里要的是一个key*/
                /*2、指定加密的秘钥*/
                .signWith(secretKey)
                .compact();

        return jws;
        //System.out.println("我的带时间的token " + jws);
    }

    /*生成秘钥方法*/
    public void getKeyString() {
        /*指定密码加密方式*/
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);

        String secretString = Encoders.BASE64.encode(key.getEncoded());
        System.out.println(secretString);

        ArrayList<String> strings = new ArrayList<>();

    }

    /*4、解析token*/
    public static Claims parseToken(String jwsString) throws HandlerException {
        /*这里把catch变量提出来了，不要怕*/
        Jws<Claims> jws=null;
        try {
            jws = Jwts.parserBuilder()
            /*这个key，ctrl+p看了一眼，能传Key 能传String*/
                    .setSigningKey(key)
                    .build()
                    /*解析的是我的加密字符串*/
                    .parseClaimsJws(jwsString);
        }
            // we can safely trust the JWT
            catch(JwtException ex){       // (5)
                // we *cannot* use the JWT as intended by its creator

                /*这里自动补货个异常，这不是坑我吗*/
                //throw ex;
               throw new HandlerException(E.COVER_THE_BOTTOM);
            }

        /*不要怕能走到这里  就说明解析出错就抛异常了*/

        /*jws能返回三个东西，自己 . 点方法出来看*/
        /*我只要身体里面的 我的自定义信息*/
        Claims body = jws.getBody();

        /* Map<String, String> yourPhone=new HashMap<String, String>();
        yourPhone.put("userPhone",userPhone);*/
        /*为什么String o = (String)claims.get(TokenUtil.TOKEN_PHONE);
        System.out.println(o);*/
        /*能直接取到电话号码*/
        /*因为传入得map集合是  k=v*/
        /*body里面都是k=v*/
        /*直接把key取出来了*/

        return body;
        }

        @Resource
        CrmTokenProperties crm;

    @Override
    public void afterPropertiesSet() throws Exception {

        TOKEN_PHONE=crm.getUserPhone();
        TOKEN_HEADER=crm.getHeaderName();
        EXP_TIME=crm.getExpTime();

    }
}
